package com.starinside.wp.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.ImmutableMap;
import com.starinside.wp.domain.AppUser;
import com.starinside.wp.domain.CheckRecord;
import com.starinside.wp.domain.RelUserChildren;
import com.starinside.wp.domain.liveRoom.LiveRoom;
import com.starinside.wp.foundation.DO.LiveRoomDO;
import com.starinside.wp.foundation.dto.AreaSettingDTO;
import com.starinside.wp.foundation.exception.BusinessException;
import com.starinside.wp.foundation.model.ErrorCode;
import com.starinside.wp.foundation.model.StatusResponse;
import com.starinside.wp.foundation.vo.BindedBabyVO;
import com.starinside.wp.repository.AppUserRepository;
import com.starinside.wp.repository.CheckRecordRepository;
import com.starinside.wp.repository.LiveRoomRepository;
import com.starinside.wp.repository.UserChildrenRepository;
import com.starinside.wp.service.LiveRoomService;
import com.starinside.wp.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.transform.Transformers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.swing.text.html.Option;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@Slf4j
public class LiveRoomServiceImpl implements LiveRoomService {

    @Autowired
    private LiveRoomRepository liveRoomRepository;

    @Autowired
    private CheckRecordRepository checkRecordRepository;


    @Autowired
    private UserChildrenRepository userChildrenRepository;

    @Autowired
    YinShiUtil yinShiUtil;

    private static final String GLOBAL_SETTING = "milepost_item";

    @Value("${sso.server.url}")
    private String ssoServerUrl;

    private static final String LIVEROOM_SWITCH_KEY = "LIVEROOM_SWITCH_KEY";

    @Override
    public List<LiveRoom> getAllValidLiveRoom(String[] childrenIds) {
        return liveRoomRepository.findByAreaIdAndChildrenId(childrenIds);
    }

    public AreaSettingDTO getAreaSetting(String label, String areaId) {
        return getAreaSetting(label, GLOBAL_SETTING, areaId);
    }

    public AreaSettingDTO getAreaSetting(String label, String type, String areaId) {
        return RemoteCallUtil.call(ssoServerUrl + "/api/sso/other_system/getAreaSetting", ImmutableMap.of("label", label, "type", type, "areaId", areaId), null, AreaSettingDTO.class, "调用sso推送消息出错");

    }

    public String getAreaYinShiToken(String areaId) {
//        return RemoteCallUtil.call(ssoServerUrl + "/api/sso/other_system/get_area_yin_shi_token",  ModelUtil.mapOf("areaId", areaId), null, String.class, "调用sso获取萤石云token出错");
        return "Not Implements yet";
    }

    @Override
    public String getLiveRoomHLSAddress(LiveRoom liveRoom) {
        String accessToken = getAreaYinShiToken(liveRoom.getAreaId());

        Map result = yinShiUtil.getCameraPlayAddress(accessToken, liveRoom.getDeviceSerial(), liveRoom.getChannelNo());

        if (result == null) {
            return null;
        }

        return (String) result.get("url");
    }

    @Override
    public LiveRoom get(String id, String areaId) {
        LiveRoom liveRoom = liveRoomRepository.getOne(id);
        if (liveRoom == null || !liveRoom.getAreaId().equals(areaId)) {
            return null;
        }
        return liveRoom;
    }

    @Override
    public LiveRoom get(String id) {
        LiveRoom liveRoom = liveRoomRepository.getOne(id);

        return liveRoom;
    }

    @Override
    public boolean childrenCameraValid(String appUserId, List<BindedBabyVO> babies) {
//        Optional<AppUser> ao = appUserRepository.findById(appUserId);
//        AppUser appUser = ao.isPresent() ? ao.get() : null;
//
//        if(appUser == null || !appUser.getCameraEnabled()){
//            return false;
//        }

        List<String> babyIds = new ArrayList<>();

        for (BindedBabyVO vo : babies) {
            RelUserChildren uc = userChildrenRepository.findFirstByChildrenIdAndUserId(vo.getId(), appUserId);
            if (uc == null || uc.getCameraEnabled() == false) {
                continue;
            }

            AreaSettingDTO s = getAreaSetting(LIVEROOM_SWITCH_KEY, vo.getAreaId());
            if (s == null || (s != null && ("true".equals(s.getValue()) || Boolean.parseBoolean(s.getValue())))) {

                //log.info("AreaSettingDTO:{}::{}, switch valid", vo, s);

                return true;
            }
        }

        //log.info("AreaSettingDTO: {}, switch invalid", babies);

        return false;
    }

    @Override
    public List<LiveRoomDO> getAllValidLiveRoomDO(List<BindedBabyVO> babies) {
        //过滤掉没有开放的宝宝幼儿园
        List<String> babyIds = new ArrayList<>();

        for (BindedBabyVO vo : babies) {
            AreaSettingDTO s = getAreaSetting(LIVEROOM_SWITCH_KEY, vo.getAreaId());
            if (s == null || (s != null && "true".equals(s.getValue()) || Boolean.parseBoolean(s.getValue()))) {
                babyIds.add(vo.getId());
            }
        }

        String[] childrenIds = babyIds.stream().toArray(String[]::new);

//        //过滤掉没有签到的宝宝
//        Date now = new Date();
//
//        String currentDay = DateUtil.millisToDateTime(now.getTime(), "yyyy-MM-dd");
//        Map<String, Date> map = DateUtil.getCurrentDayBeginAndEnd(currentDay);
//        Date begin = map.get("beg");
//        Date end = map.get("end");
//
//        List<CheckRecord> list = checkRecordRepository.findByCheckInTimeBetweenAndChildrenIdInAndCheckOutTimeIsNull(begin, end,childrenIds);
//        childrenIds = list.stream().map( k -> {
//            return k.getChildrenId();
//        }).toArray(String[] :: new );

        if (childrenIds == null || childrenIds.length == 0) {
            return new ArrayList<>();
        }

        //找到摄像头
        List<LiveRoom> ret = liveRoomRepository.findDOsByAreaIdAndChildrenId(childrenIds);
        getPlayUrl(ret);
        ResultTransformer result = Transformers.aliasToBean(LiveRoomDO.class);
        List<LiveRoomDO> DOs = result.transformList(ret);

        return DOs;
    }


    public void getPlayUrl(  List<LiveRoom>  list) {
        String SECRET_JK_3 = ""; //s3
        String SECRET_JK_2 = ""; //s2
        String SECRET_JK_1 = ""; //s1
        String SECRET_BIZ_1 = "";  //b1
        //31天有效
        long exp = System.currentTimeMillis() / 1000 + 31 * 24 * 3600;

        for (int i = 0; i <list.size(); i++) {
            LiveRoom o = list.get(i);
            String key = null;
            String url = String.valueOf(o.getUrl());
            if (null != url){
                if (url.indexOf("/s3/") >= 0 ) {
                    key = SECRET_JK_3;
                } else if (url.indexOf("/s2/") >= 0 ) {
                    key = SECRET_JK_2;
                } else if (url.indexOf("/s1/") >= 0 ) {
                    key = SECRET_JK_1;
                } else if (url.indexOf("/b1/") >= 0 ) {
                    key = SECRET_BIZ_1;
                } else {
                    continue;
                }
            }
            if (url.indexOf("?") >= 0 ){
                url =  url.substring(0,url.indexOf("?"));
            }
            String play = aAuth(url, key, exp) + "&ext=.m3u8";
            o.setUrl(play);
        }
    }


    private static String aAuth(String uri, String key, long exp) {
        String pattern = "^((rtmp://)|(http://)|(https://))?([^/?]+)(/[^?]*)?(\\\\?.*)?$";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(uri);
        String scheme = "", host = "", path = "", args = "";

        if (m.find()) {
            for (int i = 1; i < m.groupCount(); i++){
//                System.out.println(m.group(i));
            }

            scheme = m.group(1) == null ? "rtmp://" : m.group(1);
            host = m.group(4) == null ? "" : m.group(4);
            path = m.group(5) == null ? "/" : m.group(5);
            args = m.group(6) == null ? "" : m.group(6);
        } else {
            System.out.println("NO MATCH");
        }

        String rand = "0";  // "0" by default, other value is ok
        String uid = "0";   // "0" by default, other value is ok
        String sString = String.format("%s-%s-%s-%s-%s", path, exp, rand, uid, key);
        String hashValue = md5Sum(sString);
        String authKey = String.format("%s-%s-%s-%s", exp, rand, uid, hashValue);
        if (args.isEmpty()) {
            return String.format("%s%s%s%s?auth_key=%s", scheme, host, path, args, authKey);
        } else {
            return String.format("%s%s%s%s&auth_key=%s", scheme, host, path, args, authKey);
        }
    }
    private static String md5Sum(String src) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        md5.update(StandardCharsets.UTF_8.encode(src));
        return String.format("%032x", new BigInteger(1, md5.digest()));
    }
    @Override
    public void updateDate(String liveRoomId) {
        LiveRoom liveRoom = liveRoomRepository.getOne(liveRoomId);
        if (Objects.isNull(liveRoom)) {
            throw new BusinessException(ErrorCode.PARAM_CAN_NOT_BLANK, "摄像头ID错误");
        }
        liveRoom.setLastModify(new Date());
        liveRoomRepository.save(liveRoom);
    }

    private int getCameraStatus(LiveRoom liveRoom) {
        if (StringUtils.isEmpty(liveRoom.getIpUrl())
                || StringUtils.isEmpty(liveRoom.getIpChannel())
                || StringUtils.isEmpty(liveRoom.getIpAuth())) {
            return -1;
        }

//        String statusUrl = liveRoom.getIpUrl() + "jsonfile/rtmpstatus";
        String statusUrl = liveRoom.getIpUrl() + "jsonfile/rtspstatus";
        String statusJson = null;
        try {
            //{"rtmpstatus":["2","1","2","2","2","2","2","2","2","2","2","2","2","2","2","2"]}
//            {"rtspstatus":["1","1","1","1","1","1","1","2","1","2","2","2","2","2","2","2","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0","0"]}
            statusJson = HttpClientUtil.sendGet(statusUrl).toString();
        } catch (IOException e) {
            return -1;
        }

        if (StringUtils.isBlank(statusJson)) {
            return -1;
        }

        if (StringUtils.isNotEmpty(liveRoom.getIpChannel())) {
            JSONObject json = JSON.parseObject(statusJson);
            List<String> stringList = JSON.parseArray(json.getString("rtspstatus"), String.class);
            //通道状态
            int channel = Integer.parseInt(liveRoom.getIpChannel());
            if (channel >= 0 && stringList.size() > channel) {
                String s = stringList.get(channel);
                if (StringUtils.equals(s, "2")) {
                    return 1;
                }
            }

            //TODO:  同时刷新其他设备
            List<LiveRoom> rooms = liveRoomRepository.findAllByIpUrlAndIpAuthAndStatusAndActiveIsTrueAndUrlIsNotNull(
                    liveRoom.getIpUrl(), liveRoom.getIpAuth(), 1
            );

            for (int i = 0; i < rooms.size(); i++) {
                LiveRoom l = rooms.get(i);

                int c = Integer.parseInt(l.getIpChannel());

                if (c >= 0 && stringList.size() > c) {
                    String s = stringList.get(channel);
                    l.setIpOnline(StringUtils.equals(s, "2"));
                    l.setLastModify(new Date());
                }
            }

            liveRoomRepository.saveAll(rooms);
        }

        return 0;
    }

    @Async
    protected void setCameraStatusAsync(LiveRoom liveRoom, boolean online) {
        if (setCameraStatus(liveRoom, false) == 1) {
            liveRoom.setIpOnline(false);
            liveRoom.setLastModify(null);
            liveRoomRepository.save(liveRoom);
        } else {
            //就算失败也要记录最后修改时间，等待时间后重试
            liveRoom.setLastModify(null);
            liveRoomRepository.save(liveRoom);
        }
    }

    private int setCameraStatus(LiveRoom liveRoom, boolean online) {

        if (StringUtils.isEmpty(liveRoom.getIpUrl())
                || StringUtils.isEmpty(liveRoom.getIpChannel())
                || StringUtils.isEmpty(liveRoom.getIpAuth())) {
            return -1;
        }

        String val = online ? "start" : "stop";

        String url = liveRoom.getIpUrl() + "control?command=rtsp_enable_control&channel="
                + liveRoom.getIpChannel() + "&value=" + val + "&auth=" + liveRoom.getIpAuth();
        //打开摄像头
        String responseJson = null;
        try {
            responseJson = HttpClientUtil.sendPost(url, null, null).toString();
        } catch (IOException e) {
            return -1;
//            throw new BusinessException(ErrorCode.GENRAL_INTERNAL_ERROR, "物联网设备通信失败");
        }

        if (StringUtils.isBlank(responseJson)) {
            return 0;
        }

        if (responseJson.equals("ok")) {
            return 1;
        }

//        JSONObject json = JSON.parseObject(responseJson);
//        List<String> stringList = JSON.parseArray( json.getString("rtmpstatus"),String.class);
//        //通道状态
//        if (stringList.size() >= Integer.parseInt(liveRoom.getIpChannel()) ){
//            String  s = stringList.get(Integer.parseInt(liveRoom.getIpChannel()) );
//            if (StringUtils.equals(s,"2")){
//                return true;
//            }
//        }

        return 0;
    }


    //同步摄像头状态
    @Async
    protected void SyncCameraStatus(LiveRoom liveRoom) {
        //大于2分钟直接返回，防止重复调用
        if (Objects.nonNull(liveRoom.getLastModify())) {
            if (liveRoom.getLastModify().getTime() > new Date().getTime() - (1000 * 60 * 2)) {
                return;
            }
        }

        //先保存修改时间
        liveRoom.setLastModify(new Date());
        liveRoomRepository.save(liveRoom);

        int ret = getCameraStatus(liveRoom);

        if (ret == -1) {
            //数据不全
        } else if (ret == 1) {
            if (!liveRoom.getIpOnline()) {
                liveRoom.setIpOnline(true);
                liveRoom.setPlayerHeartBeat(new Date());
                liveRoomRepository.save(liveRoom);
            }
        } else if (liveRoom.getIpOnline()) {
            //不在线
            liveRoom.setIpOnline(false);
            liveRoomRepository.save(liveRoom);
        }
    }

    @Override
    public Integer openLive(LiveRoom liveRoom) {
        if (Objects.isNull(liveRoom)) {
            throw new BusinessException(ErrorCode.PARAM_CAN_NOT_BLANK, "摄像头ID错误");
        }

        //打开摄像头
        if (liveRoom.getIpOnline()) {
            SyncCameraStatus(liveRoom);
            return 1;
        }

        int status = setCameraStatus(liveRoom, true);
        //设置状态
        if (status == 1) {
            liveRoom.setIpOnline(true);
            liveRoom.setPlayerHeartBeat(new Date());
            liveRoom.setLastModify(new Date());
            liveRoomRepository.save(liveRoom);
            liveRoomRepository.flush();

            try {
                TimeUnit.SECONDS.sleep(20); //强行睡眠30秒等待推流。
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            return 0;
        }
        //摄像头处于无法打开时候抛出异常
        if (status == -1) {
            throw new BusinessException(ErrorCode.GENRAL_INTERNAL_ERROR, "物联网设备通信失败");
        }

        return 1; //设置失败的时候仍然通知前端立即打开
    }

    @Override
    public Integer openLive(String areaId, String liveRoomId) {
        LiveRoom liveRoom = liveRoomRepository.findByIdAndAreaId(liveRoomId, areaId);
        return openLive(liveRoom);
    }
}
